//===============================================================================
// Microsoft patterns & practices
// Mobile Client Software Factory - July 2006
//===============================================================================
// Copyright  Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===============================================================================
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious.  No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
//===============================================================================

using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using Microsoft.Practices.Mobile.ConnectionMonitor;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.Practices.TestUtilities;

namespace Microsoft.Practices.Mobile.DisconnectedAgent.Tests
{
	[TestClass]
	public class ConnectionMonitorAdapterFixture
	{
		[TestMethod]
		public void CreatesAdapterHooksConnectionStatusChangedEvent()
		{
			MockConnection connectionA = new MockConnection("ConnA", 9,"Network1");
			MockConnection connectionB = new MockConnection("ConnB", 3, "Network2");
			ConnectionMonitor.ConnectionMonitor connectionMonitor = new ConnectionMonitor.ConnectionMonitor();
			connectionMonitor.Connections.Add(connectionA);
			connectionMonitor.Connections.Add(connectionB);

			ConnectionMonitorAdapter adapter = new ConnectionMonitorAdapter(connectionMonitor);
			int firedCount = 0;

			adapter.ConnectionStatusChanged += delegate(Object sender, EventArgs args)
				{
					firedCount++;
				};

			Assert.IsFalse(connectionMonitor.IsConnected);
			Assert.AreEqual(0, firedCount);

			connectionA.MockConnect(); //Forcibly connect the connectionA and change connection status
		}

		[TestMethod]
		public void AdapterFiresConnectionStatusChangedOnlyWhenGetConnected()
		{
			MockConnection connectionA = new MockConnection("ConnA", 9, "Network1");
			MockConnection connectionB = new MockConnection("ConnB", 3, "Network2");
			ConnectionMonitor.ConnectionMonitor connectionMonitor = new ConnectionMonitor.ConnectionMonitor();
			connectionMonitor.Connections.Add(connectionA);
			connectionMonitor.Connections.Add(connectionB);

			ConnectionMonitorAdapter adapter = new ConnectionMonitorAdapter(connectionMonitor);
			int firedCount = 0;

			adapter.ConnectionStatusChanged += delegate(Object sender, EventArgs args)
				{
					firedCount++;
				};

			Assert.IsFalse(connectionMonitor.IsConnected);
			Assert.AreEqual(0, firedCount);

			connectionA.MockConnect(); //Forcibly connect the connectionA and change connection status
			Assert.AreEqual(1, firedCount);
			connectionA.MockDisconnect();
			Assert.AreEqual(1, firedCount);
			connectionB.MockConnect();
			Assert.AreEqual(2, firedCount);
			connectionB.MockDisconnect();
			Assert.AreEqual(2, firedCount);
		}

		[TestMethod]
		public void GetCurrentConnectionPriceGetsTheManagerConnectionStatus()
		{
			MockConnection connectionA = new MockConnection("ConnA", 9, "Network1");
			MockConnection connectionB = new MockConnection("ConnB", 3, "Network2");
			ConnectionMonitor.ConnectionMonitor connectionMonitor = new ConnectionMonitor.ConnectionMonitor();
			connectionMonitor.Connections.Add(connectionA);
			connectionMonitor.Connections.Add(connectionB);

			ConnectionMonitorAdapter adapter = new ConnectionMonitorAdapter(connectionMonitor);

			Assert.IsFalse(connectionMonitor.IsConnected);
			Assert.IsFalse(adapter.IsConnected);
			Assert.AreEqual(connectionMonitor.IsConnected, adapter.IsConnected);

			connectionA.MockConnect(); //Forcibly connect the connectionA and change connection status
			Assert.IsTrue(adapter.IsConnected);
			Assert.AreEqual(connectionMonitor.IsConnected, adapter.IsConnected);
			connectionA.MockDisconnect();
			Assert.IsFalse(adapter.IsConnected);
			Assert.AreEqual(connectionMonitor.IsConnected, adapter.IsConnected);
			connectionB.MockConnect();
			Assert.IsTrue(adapter.IsConnected);
			Assert.AreEqual(connectionMonitor.IsConnected, adapter.IsConnected);
			connectionB.MockDisconnect();
			Assert.IsFalse(adapter.IsConnected);
			Assert.AreEqual(connectionMonitor.IsConnected, adapter.IsConnected);
		}

		[TestMethod]
		public void GetCurrentConnectionPriceGetsTheManagerConnectionPrice()
		{
			MockConnection connectionA = new MockConnection("ConnA", 9, "Network1");
			MockConnection connectionB = new MockConnection("ConnB", 3, "Network2");
			ConnectionMonitor.ConnectionMonitor connectionMonitor = new ConnectionMonitor.ConnectionMonitor();
			connectionMonitor.Connections.Add(connectionA);
			connectionMonitor.Connections.Add(connectionB);

			ConnectionMonitorAdapter adapter = new ConnectionMonitorAdapter(connectionMonitor);

			Assert.IsFalse(connectionMonitor.IsConnected);
			Assert.IsFalse(adapter.IsConnected);
			Assert.AreEqual(connectionMonitor.IsConnected, adapter.IsConnected);

			connectionA.MockConnect(); //Forcibly connect the connectionA and change connection status
			Assert.AreEqual((uint)9, adapter.CurrentConnectionPrice);
			Assert.AreEqual((uint)9, connectionMonitor.ActiveConnections.First().Price);
			connectionA.MockDisconnect();
			connectionB.MockConnect();
			Assert.AreEqual((uint)3, adapter.CurrentConnectionPrice);
			Assert.AreEqual((uint)3, connectionMonitor.ActiveConnections.First().Price);
		}

		[TestMethod]
		public void GetCurrentNetworkNameGetsTheManagerNetworkName()
		{
			MockConnection connectionA = new MockConnection("ConnA", 9, "Network1");
			MockConnection connectionB = new MockConnection("ConnB", 3, "Network2");
			ConnectionMonitor.ConnectionMonitor connectionMonitor = new ConnectionMonitor.ConnectionMonitor();
			connectionMonitor.Connections.Add(connectionA);
			connectionMonitor.Connections.Add(connectionB);

			ConnectionMonitorAdapter adapter = new ConnectionMonitorAdapter(connectionMonitor);

			Assert.IsFalse(connectionMonitor.IsConnected);
			Assert.IsFalse(adapter.IsConnected);
			Assert.AreEqual(connectionMonitor.IsConnected, adapter.IsConnected);

			connectionA.MockConnect(); //Forcibly connect the connectionA and change connection status
			Assert.AreEqual("Network1", adapter.CurrentNetwork);
			Assert.AreEqual(adapter.CurrentNetwork, connectionMonitor.ActiveConnections.First().GetNetworkName());
			connectionA.MockDisconnect();
			connectionB.MockConnect();
			Assert.AreEqual("Network2", adapter.CurrentNetwork);
			Assert.AreEqual(adapter.CurrentNetwork, connectionMonitor.ActiveConnections.First().GetNetworkName());
		}

		[TestMethod]
		public void AdapterDisposeReleasesEventHandler()
		{
			MockConnection connectionA = new MockConnection("ConnA", 9, "Network1");
			MockConnection connectionB = new MockConnection("ConnB", 3, "Network2");
			ConnectionMonitor.ConnectionMonitor connectionMonitor = new ConnectionMonitor.ConnectionMonitor();
			connectionMonitor.Connections.Add(connectionA);
			connectionMonitor.Connections.Add(connectionB);

			ConnectionMonitorAdapter adapter = new ConnectionMonitorAdapter(connectionMonitor);
			int firedCount = 0;

			adapter.ConnectionStatusChanged += delegate(Object sender, EventArgs args)
				{
					firedCount++;
				};

			Assert.IsFalse(connectionMonitor.IsConnected);
			Assert.AreEqual(0, firedCount);

			connectionA.MockConnect();
			Assert.AreEqual(1, firedCount);
			connectionA.MockDisconnect();
			Assert.AreEqual(1, firedCount);

			//Dispose adapter
			adapter.Dispose();

			connectionB.MockConnect();
			Assert.AreEqual(1, firedCount);
			connectionB.MockDisconnect();
			Assert.AreEqual(1, firedCount);
		}

		[TestMethod]
		public void GetCurrentConnectionPriceThrowsObjectDisposedExceptionIfAdapterIsDisposed()
		{
			ConnectionMonitor.ConnectionMonitor connectionMonitor = new ConnectionMonitor.ConnectionMonitor();
			ConnectionMonitorAdapter adapter = new ConnectionMonitorAdapter(connectionMonitor);
			adapter.Dispose();
			ExtendedAssert.Throws<ObjectDisposedException>(
						delegate { uint price = adapter.CurrentConnectionPrice; });//Should throw an ObjectDisposedException
		}

		[TestMethod]
		public void GetCurrentNetworkThrowsObjectDisposedExceptionIfAdapterIsDisposed()
		{
			ConnectionMonitor.ConnectionMonitor connectionMonitor = new ConnectionMonitor.ConnectionMonitor();
			ConnectionMonitorAdapter adapter = new ConnectionMonitorAdapter(connectionMonitor);
			adapter.Dispose();
			ExtendedAssert.Throws<ObjectDisposedException>(
						delegate { string network = adapter.CurrentNetwork; });//Should throw an ObjectDisposedException
		}

		[TestMethod]
		public void GetIsConnectedThrowsObjectDisposedExceptionIfAdapterIsDisposed()
		{
			ConnectionMonitor.ConnectionMonitor connectionMonitor = new ConnectionMonitor.ConnectionMonitor();
			ConnectionMonitorAdapter adapter = new ConnectionMonitorAdapter(connectionMonitor);
			adapter.Dispose();
			ExtendedAssert.Throws<ObjectDisposedException>(
						delegate { bool connected = adapter.IsConnected; });//Should throw an ObjectDisposedException
		}

		[TestMethod]
		public void DisposeThrowsObjectDisposedExceptionIfAdapterIsDisposed()
		{
			ConnectionMonitor.ConnectionMonitor connectionMonitor = new ConnectionMonitor.ConnectionMonitor();
			ConnectionMonitorAdapter adapter = new ConnectionMonitorAdapter(connectionMonitor);
			adapter.Dispose();
			ExtendedAssert.Throws<ObjectDisposedException>(
						delegate { adapter.Dispose(); }); //Should throw an ObjectDisposedException
		}

		[TestMethod]
		public void CurrentNetworkReturnsNullIfThereIsNotActiveNetwork()
		{
			ConnectionMonitor.ConnectionMonitor connectionMonitor = new ConnectionMonitor.ConnectionMonitor();
			ConnectionMonitorAdapter adapter = new ConnectionMonitorAdapter(connectionMonitor);
			Assert.IsFalse(adapter.IsConnected);
			Assert.IsNull(adapter.CurrentNetwork);
		}

		[TestMethod]
		public void CurrentConnectionPriceThrowsInvalidOperationExceptionIfNotConnected()
		{
			ConnectionMonitor.ConnectionMonitor connectionMonitor = new ConnectionMonitor.ConnectionMonitor();
			ConnectionMonitorAdapter adapter = new ConnectionMonitorAdapter(connectionMonitor);
			Assert.IsFalse(adapter.IsConnected);
			ExtendedAssert.Throws<InvalidOperationException>(
						delegate { uint mockPrice = adapter.CurrentConnectionPrice; });//Should throw an InvalidOperationException
		}
	}


	public class MockConnection : Connection
	{
		string networkName;
		bool isConnected;

		public MockConnection(string connectionType, uint price, string networkName)
			: base(connectionType, price)
		{
			this.networkName = networkName;
			isConnected = false;
		}
		public override bool IsConnected
		{
			get { return isConnected; }
		}

		public override string GetNetworkName()
		{
			return networkName;
		}

		public override string GetDetailedInfoString()
		{
			return string.Empty;
		}

		internal void MockConnect()
		{
			isConnected = true;
			base.RaiseStateChanged(new StateChangedEventArgs(isConnected, networkName));
		}

		internal void MockDisconnect()
		{
			isConnected = false;
			base.RaiseStateChanged(new StateChangedEventArgs(isConnected, networkName));
		}
	}
}
